/**
 * 
 */
package t4j.concurrency;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Horse implements Runnable {
	private static int counter = 0;
	private final int id = counter++;
	private int strides = 0;
	private static Random rand = new Random(47);
	private static CyclicBarrier barrier;

	public Horse(CyclicBarrier b) {
		barrier = b;
	}

	public synchronized int getStrides() {
		return strides;//已跑数
	}

	public void run() {

		try {
			while (!Thread.interrupted()) {
				synchronized (this) {
					strides += rand.nextInt(3);//随机3以内，累计已跑数
				}

				barrier.await();//阻塞，直到CyclicBarrier的计数值为0时
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (BrokenBarrierException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public String toString() {
		return "Horse " + id + " ";
	}

	//轨迹
	public String tracks() {
		StringBuilder s = new StringBuilder();

		for (int i = 0; i < getStrides(); i++)
			s.append("*");

		s.append(id);

		return s.toString();
	}
}

public class HorseRace {
	static final int FINISH_LINE = 75;
	private List<Horse> horses = new ArrayList<Horse>();
	private ExecutorService exec = Executors.newCachedThreadPool();

	private CyclicBarrier barrier;//实现“栅栏动作”。这个与CountDownLatch不同在于，当CyclicBarrier的计数值为0时，可以重用。

	public HorseRace(int nHorses, final int pause) {
		
		barrier = new CyclicBarrier(nHorses, new Runnable() {

			//这里的匿名类实现Runnable，是当CyclicBarrier为0时，自动执行的。等马全部跑完一次了，再打印整个轨迹。这也与CountDownLatch的另一个区别
			@Override
			public void run() {
				StringBuilder s = new StringBuilder();
		
				for (int i = 0; i < FINISH_LINE; i++)
					s.append("=");

				System.out.println(s);		//输出75个等号

				for (Horse horse : horses)
					System.out.println(horse.tracks());//打印马的轨迹*

				for (Horse horse : horses)
					if (horse.getStrides() >= FINISH_LINE) {//循环所有马，判断某一个马到达终点就算赢
						System.out.println(horse + "won!");
						exec.shutdownNow();
						return;
					}

				try {
					TimeUnit.MILLISECONDS.sleep(pause);//每次打印后，停顿一会
				} catch (InterruptedException e) {
					System.out.println("barrier-action sleep interrupted");
				}

			}
		});

		for (int i = 0; i < nHorses; i++) {
			Horse horse = new Horse(barrier);//创建马
			horses.add(horse);//把马加入list
			exec.execute(horse);//线程运行马
		}

	}

	public static void main(String[] args) {
		int nHorses = 7;
		int pause = 200;

		new HorseRace(nHorses, pause);
	}

}
